package com.zf.yichat.service.impl;

import com.zf.yichat.dto.StAnswersDto;
import com.zf.yichat.dto.StQuestionsDto;
import com.zf.yichat.dto.UserAnswerDto;
import com.zf.yichat.mapper.*;
import com.zf.yichat.model.*;
import com.zf.yichat.service.PlantTreeService;
import com.zf.yichat.service.SysDictService;
import com.zf.yichat.service.UserAnswerService;
import com.zf.yichat.utils.common.DateUtils;
import com.zf.yichat.utils.common.DtoChangeUtils;
import com.zf.yichat.utils.common.FsConst;
import com.zf.yichat.utils.response.FsResponse;
import com.zf.yichat.utils.response.FsResponseGen;
import com.zf.yichat.vo.DictKey;
import com.zf.yichat.vo.IntegralType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserAnswerServiceImpl implements UserAnswerService {

    @Autowired
    private StQuestionsMapper questionsMapper;

    @Autowired
    private StAnswersMapper answersMapper;

    @Autowired
    private StUserAnswersMapper userAnswersMapper;

    @Autowired
    private SysDictService sysDictService;

    @Autowired
    private UserIntegralDetailMapper userIntegralDetailMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StLowCarbonKnowledgeMapper lowCarbonKnowledgeMapper;

    @Autowired
    private StLowCarbonApplyCertificateMapper lowCarbonApplyCertificateMapper;

    @Autowired
    private PlantTreeService plantTreeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StQuestionsDto queryQuestionList(Long userId) {

        Calendar calendar = Calendar.getInstance();
        String todayDate = DateUtils.formatDate(calendar.getTime(), "yyyy-MM-dd");
        Example example = new Example(StQuestions.class);
        example.createCriteria().andEqualTo("releaseTime", todayDate);
        StQuestions stQuestions = questionsMapper.selectOneByExample(example);
        if (null == stQuestions) {
            StQuestions randomQuestions = questionsMapper.selectRandomQuestion();
            Integer randomQuestionsId = randomQuestions.getId();
            List<StAnswers> list = answersMapper.selectAnswersByQuestionId(randomQuestionsId);

            // 随机获取已配置的题目设置为今日题目
            StQuestions questions = new StQuestions();
            questions.setType(randomQuestions.getType());
            questions.setTitle(randomQuestions.getTitle());
            questions.setCreateTime(new Date());
            questions.setReleaseTime(DateUtils.getSpecificDate());
            questionsMapper.insertSelective(questions);

            Integer questionsId = questions.getId();
            // 新增答案
            for (StAnswers answers : list) {
                StAnswers stAnswers = new StAnswers();
                stAnswers.setNumber(answers.getNumber());
                stAnswers.setCorrect(answers.getCorrect());
                stAnswers.setCreateTime(new Date());
                stAnswers.setAnswer(answers.getAnswer());
                stAnswers.setQuestionId(questionsId);
                answersMapper.insertSelective(stAnswers);
            }

            // 重置问题
            questions.setId(questionsId);
            stQuestions = questions;
        }


        StQuestionsDto dto = new StQuestionsDto();
        BeanUtils.copyProperties(stQuestions, dto);
        Integer questionsId = stQuestions.getId();
        // 查询对应题目
        List<StAnswers> list = answersMapper.selectAnswersByQuestionId(questionsId);
        dto.setAnswersList(list);

        // 查询用户是否已经答过该题目
        Example exampleAnswer = new Example(StUserAnswers.class);
        exampleAnswer.createCriteria().andEqualTo("userId", userId).andEqualTo("questionId", questionsId);
        List<StUserAnswers> userAnswers = userAnswersMapper.selectByExample(exampleAnswer);
        if (null != userAnswers && userAnswers.size() > 0) {
            dto.setAnswerState(StQuestionsDto.answer_YES);
            StUserAnswers stUserAnswers = userAnswers.get(0);
            dto.setSelectedId(stUserAnswers.getAnswerId());
            dto.setScore(stUserAnswers.getScore());

        }else {
            dto.setAnswerState(StQuestionsDto.answer_NO);
        }

        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FsResponse userAnswerQuestion(Long userId, Integer answerId) {

        // 查询今天是否答题
        StUserAnswers answersToday =  userAnswersMapper.queryAnswerTheQuestionToday(userId);
        if (null != answersToday) {
            return FsResponseGen.failMsg("您今日已经答过题，不允许重复答题！");
        }

        // 查询答案是否存在
        StAnswers answers = answersMapper.selectByPrimaryKey(answerId);
        if (null == answers) {
            return FsResponseGen.failMsg("答案不存在！");
        }

        Integer questionId = answers.getQuestionId();
        StQuestions questions = questionsMapper.selectByPrimaryKey(questionId);
        if (null == questions) {
            return FsResponseGen.failMsg("题目不存在");
        }

        // 查询用户是否已经答过该题目
        Example example = new Example(StUserAnswers.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("questionId", questionId);
        List<StUserAnswers> userAnswers = userAnswersMapper.selectByExample(example);
        if (null != userAnswers && userAnswers.size() > 0) {
            return FsResponseGen.failMsg("您已经答过该题目，不允许重复答题！");
        }

        StAnswersDto dto = new StAnswersDto();
        String correct = answers.getCorrect();
        dto.setCorrect(StAnswers.CORRECT_TRUE.equals(correct));

        // 回答正确
        if (StAnswers.CORRECT_TRUE.equals(correct)) {
            dto.setAnswers(answers);

            // 赠送一次浇水次数
            plantTreeService.addTask(userId, "答题正确", UserPrintTreeTask.ANSWER_TASK, 1);
        }else {
            // 回答错误，将正确答案返回
            Example exampleAnswer = new Example(StAnswers.class);
            exampleAnswer.createCriteria().andEqualTo("correct", StAnswers.CORRECT_TRUE).andEqualTo("questionId", questionId);
            StAnswers stAnswers = answersMapper.selectOneByExample(exampleAnswer);
            dto.setAnswers(stAnswers);
        }

        // 存储用户答题结果
        StUserAnswers stUserAnswers = new StUserAnswers();
        stUserAnswers.setQuestionId(questionId);
        stUserAnswers.setAnswerId(answerId);
        stUserAnswers.setCorrect(correct);
        stUserAnswers.setUserId(userId);
        stUserAnswers.setCreateTime(new Date());
        userAnswersMapper.insertSelective(stUserAnswers);

        // 赠送积分
        BigDecimal score = new BigDecimal(Optional.ofNullable(sysDictService.selectOne(DictKey.user_answer_initial_value)).map(SysDict::getValue).orElse("20"));
        int intScore = score.intValue();
        // 正确与错误比例
        BigDecimal rate = new BigDecimal(Optional.ofNullable(sysDictService.selectOne(DictKey.user_answer_conversion_rate)).map(SysDict::getValue).orElse("0.5"));
        int intRate = rate.intValue();
        // 回答正确赠送积分值
        BigDecimal trueScore = new BigDecimal(Optional.ofNullable(sysDictService.selectOne(DictKey.user_answer_true_value)).map(SysDict::getValue).orElse("10"));
        int intTrueScore = trueScore.intValue();

        // 判断用户答题连续天数，按照答错+1 答对+10的规则进行赠送
        // 查询用户所有的答题记录
        Example exampleUserAnswer = new Example(StUserAnswers.class);
        exampleUserAnswer.createCriteria().andEqualTo("userId", userId);
        exampleUserAnswer.setOrderByClause("create_time desc");
        List<StUserAnswers> userAnswersList = userAnswersMapper.selectByExample(exampleUserAnswer);

        int consecutiveDays = calculateConsecutiveDays(userAnswersList);
        // 第一天或有间隔
        if (consecutiveDays == 1) {
            //添加获取积分
            BigDecimal realityScore = StAnswers.CORRECT_TRUE.equals(correct) ? score : (score.multiply(rate));
            updateIntegralDetail(IntegralType.ANSWER_QUESTION, questionId.toString(), realityScore.intValue(), userId);

            dto.setScore(realityScore.intValue());

            // 更新用户答题表的奖励
            StUserAnswers answers1 = new StUserAnswers();
            answers1.setId(stUserAnswers.getId());
            answers1.setScore(realityScore.intValue());
            userAnswersMapper.updateByPrimaryKeySelective(answers1);
        }
        else {
            //添加获取积分 -- 连续赠送值
            Integer incrementalScore = consecutiveDays * intTrueScore;
            incrementalScore = intScore + incrementalScore;

            BigDecimal inScore = new BigDecimal(incrementalScore);
            BigDecimal realityScore = StAnswers.CORRECT_TRUE.equals(correct) ? inScore : (inScore.multiply(rate));
            updateIntegralDetail(IntegralType.ANSWER_QUESTION, questionId.toString(), realityScore.intValue(), userId);

            dto.setScore(realityScore.intValue());

            // 更新用户答题表的奖励
            StUserAnswers answers1 = new StUserAnswers();
            answers1.setId(stUserAnswers.getId());
            answers1.setScore(realityScore.intValue());
            userAnswersMapper.updateByPrimaryKeySelective(answers1);
        }

        return FsResponseGen.successData(dto);
    }

    @Override
    public FsResponse questionList() {

        Example exampleUserAnswer = new Example(StQuestions.class);
        exampleUserAnswer.setOrderByClause("release_time asc");
        List<StQuestions> questionsList = questionsMapper.selectByExample(exampleUserAnswer);

        return DtoChangeUtils.getPageList(questionsList, data-> {
            StQuestions questions = new StQuestions();
            BeanUtils.copyProperties(data, questions);
            return questions;
        });
    }

    @Override
    public void addStQuestions(StQuestions questions) {
        questions.setCreateTime(new Date());
        questions.setType("carbon");
        questionsMapper.insertSelective(questions);
    }

    @Override
    public void editStQuestions(StQuestions questions) {
        questionsMapper.updateByPrimaryKeySelective(questions);
    }

    @Override
    public void deleteStQuestions(Integer id) {
        questionsMapper.deleteByPrimaryKey(id);
    }

    @Override
    public FsResponse answerList(Integer questionId) {
        Example example = new Example(StAnswers.class);
        example.createCriteria().andEqualTo("questionId", questionId);
        example.setOrderByClause("number asc");
        List<StAnswers> list = answersMapper.selectByExample(example);
        return FsResponseGen.successData(list);
    }

    @Override
    public void addStAnswers(StAnswers answers) {
        answers.setCreateTime(new Date());
        answersMapper.insertSelective(answers);
    }

    @Override
    public void editStAnswers(StAnswers answers) {
        answersMapper.updateByPrimaryKeySelective(answers);
    }

    @Override
    public void deleteStAnswers(Integer id) {
        answersMapper.deleteByPrimaryKey(id);
    }

    @Override
    public UserAnswerDto queryUserAnswerCount(Long userId) {
        Example exampleAnswer = new Example(StUserAnswers.class);
        exampleAnswer.createCriteria().andEqualTo("userId", userId).andEqualTo("correct", StAnswers.CORRECT_TRUE);
        List<StUserAnswers> stUserAnswers = userAnswersMapper.selectByExample(exampleAnswer);

        int trueCount = stUserAnswers.size();
        BigDecimal answerNum = new BigDecimal(Optional.ofNullable(sysDictService.selectOne(DictKey.user_answer_apply_cert_num)).map(SysDict::getValue).orElse("7"));

        // 查询是否已申请
        Example example = new Example(StLowCarbonApplyCertificate.class);
        example.createCriteria().andEqualTo("userId", userId);
        StLowCarbonApplyCertificate carbonApplyCertificate = lowCarbonApplyCertificateMapper.selectOneByExample(example);

        UserAnswerDto answerDto = new UserAnswerDto();
        answerDto.setTrueAnswerCount(trueCount);
        answerDto.setApply(trueCount >= answerNum.intValue() && null == carbonApplyCertificate);
        answerDto.setApplied(null != carbonApplyCertificate);
        return answerDto;
    }

    @Override
    public FsResponse queryStLowCarbonKnowledgeList() {
        Example exampleUserAnswer = new Example(StLowCarbonKnowledge.class);
        List<StLowCarbonKnowledge> knowledgeList = lowCarbonKnowledgeMapper.selectByExample(exampleUserAnswer);

        return DtoChangeUtils.getPageList(knowledgeList, data-> {
            StLowCarbonKnowledge knowledge = new StLowCarbonKnowledge();
            BeanUtils.copyProperties(data, knowledge);
            return knowledge;
        });
    }

    @Override
    public FsResponse userApplyCertificate(StLowCarbonApplyCertificate certificate) {

        Example example = new Example(StLowCarbonApplyCertificate.class);
        example.createCriteria().andEqualTo("userId", certificate.getUserId());
        StLowCarbonApplyCertificate carbonApplyCertificate = lowCarbonApplyCertificateMapper.selectOneByExample(example);
        if (null != carbonApplyCertificate) {
            return FsResponseGen.successData(carbonApplyCertificate);
        }

        certificate.setStatus(FsConst.Status.EFFECT);
        certificate.setCreateTime(new Date());
        return FsResponseGen.successData(lowCarbonApplyCertificateMapper.insertSelective(certificate));
    }

    /**
     * 更新用户积分
     * @param type
     * @param referId
     * @param score
     * @param userId
     */
    private void updateIntegralDetail(IntegralType type, String referId, Integer score, Long userId) {

        //增加用户积分记录
        UserIntegralDetail detail = new UserIntegralDetail();
        detail.setIntegral(score);
        detail.setReferType(type.getVal());
        detail.setMemo(type.getDesc());
        detail.setUserId(userId);
        detail.setReferId(referId);
        userIntegralDetailMapper.insertSelective(detail);

        //更新user表的积分值
        userMapper.addIntegral(score, userId);

    }

    /**
     * 计算连续答题的天数
     */
    private int calculateConsecutiveDays (List<StUserAnswers> userAnswerList) {
        int consecutiveDays = 0;
        int currentStreak = 0;
        Date currentDate = new Date();

        for (StUserAnswers answers : userAnswerList) {
            // 计算当前记录距离今天的天数
            long daysDiff = daysBetween(answers.getCreateTime(), currentDate);

            if (daysDiff == currentStreak) {
                // 连续答题
                currentStreak++;
            } else {
                // 重置连续答题计数
                currentStreak = 0;
            }

            if (currentStreak > consecutiveDays) {
                consecutiveDays = currentStreak;
            }
        }

        return consecutiveDays;
    }

    private long daysBetween (Date date1, Date date2) {
        long diffInMillies = date2.getTime () - date1.getTime ();
        return TimeUnit.DAYS.convert (diffInMillies, TimeUnit.MILLISECONDS);
    }
}
